package ynu.edu.merchant.service.impl;

import cn.hutool.core.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ynu.edu.common.exception.BusinessException;
import ynu.edu.merchant.dto.MerchantReviewDTO;
import ynu.edu.merchant.entity.Merchant;
import ynu.edu.merchant.entity.MerchantReview;
import ynu.edu.merchant.repository.MerchantRepository;
import ynu.edu.merchant.repository.MerchantReviewRepository;
import ynu.edu.merchant.service.MerchantReviewService;
import ynu.edu.merchant.vo.MerchantReviewVO;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Optional;

/**
 * 商家评价服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MerchantReviewServiceImpl implements MerchantReviewService {

    private final MerchantReviewRepository reviewRepository;
    private final MerchantRepository merchantRepository;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MerchantReviewVO createReview(MerchantReviewDTO reviewDTO) {
        // 检查商家是否存在
        Merchant merchant = merchantRepository.findById(reviewDTO.getMerchantId())
                .orElseThrow(() -> new BusinessException("商家不存在"));

        // 检查是否已经评价过
        Optional<MerchantReview> existReview = reviewRepository.findByOrderId(reviewDTO.getOrderId());
        if (existReview.isPresent()) {
            throw new BusinessException("该订单已评价，不能重复评价");
        }

        // 创建评价实体
        MerchantReview review = new MerchantReview();
        BeanUtil.copyProperties(reviewDTO, review);

        // 保存评价
        review = reviewRepository.save(review);

        // 更新商家评分
        updateMerchantRating(merchant.getId());

        // 返回评价信息
        return convertToVO(review);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MerchantReviewVO updateReview(MerchantReviewDTO reviewDTO) {
        // 检查评价是否存在
        MerchantReview review = reviewRepository.findById(reviewDTO.getId())
                .orElseThrow(() -> new BusinessException("评价不存在"));

        // 更新评价信息
        BeanUtil.copyProperties(reviewDTO, review, "id", "merchantId", "userId", "orderId", "createTime", "updateTime", "isDeleted");

        // 保存评价
        review = reviewRepository.save(review);

        // 更新商家评分
        updateMerchantRating(review.getMerchantId());

        // 返回评价信息
        return convertToVO(review);
    }

    @Override
    public MerchantReviewVO getReviewById(Long id) {
        MerchantReview review = reviewRepository.findById(id)
                .orElseThrow(() -> new BusinessException("评价不存在"));
        return convertToVO(review);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteReview(Long id) {
        MerchantReview review = reviewRepository.findById(id)
                .orElseThrow(() -> new BusinessException("评价不存在"));
        review.setIsDeleted(1);
        reviewRepository.save(review);

        // 更新商家评分
        updateMerchantRating(review.getMerchantId());

        return true;
    }

    @Override
    public Page<MerchantReviewVO> getReviewsByMerchantId(Long merchantId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createTime"));
        Page<MerchantReview> reviewPage = reviewRepository.findByMerchantIdAndStatusAndIsDeleted(
                merchantId, 1, 0, pageable);
        return reviewPage.map(this::convertToVO);
    }

    @Override
    public Page<MerchantReviewVO> getReviewsByUserId(Long userId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createTime"));
        Page<MerchantReview> reviewPage = reviewRepository.findByUserIdAndIsDeleted(
                userId, 0, pageable);
        return reviewPage.map(this::convertToVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean replyReview(Long id, String reply) {
        MerchantReview review = reviewRepository.findById(id)
                .orElseThrow(() -> new BusinessException("评价不存在"));
        review.setReply(reply);
        review.setReplyTime(LocalDateTime.now());
        reviewRepository.save(review);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateReviewStatus(Long id, Integer status) {
        MerchantReview review = reviewRepository.findById(id)
                .orElseThrow(() -> new BusinessException("评价不存在"));
        review.setStatus(status);
        reviewRepository.save(review);

        // 更新商家评分
        updateMerchantRating(review.getMerchantId());

        return true;
    }

    @Override
    public BigDecimal calculateAverageRating(Long merchantId) {
        BigDecimal avgRating = reviewRepository.calculateAverageRating(merchantId, 1, 0);
        return avgRating != null ? avgRating : BigDecimal.valueOf(5.0);
    }

    @Override
    public long countReviewsByMerchantId(Long merchantId) {
        return reviewRepository.countByMerchantIdAndStatusAndIsDeleted(merchantId, 1, 0);
    }

    /**
     * 更新商家评分
     *
     * @param merchantId 商家ID
     */
    private void updateMerchantRating(Long merchantId) {
        BigDecimal avgRating = calculateAverageRating(merchantId);
        Merchant merchant = merchantRepository.findById(merchantId).orElse(null);
        if (merchant != null) {
            merchant.setRating(avgRating);
            merchantRepository.save(merchant);
        }
    }

    /**
     * 将评价实体转换为VO
     *
     * @param review 评价实体
     * @return 评价VO
     */
    private MerchantReviewVO convertToVO(MerchantReview review) {
        MerchantReviewVO reviewVO = new MerchantReviewVO();
        BeanUtil.copyProperties(review, reviewVO);

        // 设置商家名称
        merchantRepository.findById(review.getMerchantId())
                .ifPresent(merchant -> reviewVO.setMerchantName(merchant.getName()));

        // 用户信息需要通过远程调用获取，这里暂时不实现

        return reviewVO;
    }
} 